/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.admin.addins;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.ListChoice;
import org.apache.wicket.markup.html.form.ListMultipleChoice;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.Model;
import org.gidoo.cms.admin.AdminPage;
import org.gidoo.cms.helper.Crypto;
import org.gidoo.cms.login.GidooCMSSession;

/**
 * A panel where you can adminstrate a certain user.
 * @author Thomas
 */
public class SingleUserPanel extends AddInPanel
{
  
  private Form formDelete;
  private Form formPublish;
  private Form formEdit;
  private Form formChange;
  
  private Button btDelete;
  
  private ListMultipleChoice listPublishAllowed;
  private ListMultipleChoice listOtherSectionsPublish;
  private AjaxButton btPublish;
  private AjaxButton btDePublish;
  
  private ListMultipleChoice listEditAllowed;
  private ListMultipleChoice listOtherSectionsEdit;
  private AjaxButton btEdit;
  private AjaxButton btDeEdit;
  
  private TextField txtRealName;
  private TextField txtEMail;
  private PasswordTextField txtPassword1;
  private PasswordTextField txtPassword2;
  private CheckBox cbIsAdmin;
  private Button btChange;
  
  private AdminPage theParent;
  private String theUserID;
  
  /**
   * Creates a new instance of UsersPanel.
   *
   * @param id The wicket id.
   * @param userID The id (username) of the user.
   */
  public SingleUserPanel(String id, String userID, AdminPage parent)
  {
    super(id);
    
    final GidooCMSSession session = (GidooCMSSession) getSession();
    
    
    this.theUserID = userID;
    this.theParent = parent;
    
    lblTitle.setModelObject((String) lblTitle.getModelObject() + userID);
    
    formDelete = new Form("formDelete");
    btDelete = new Button("btDelete", new Model(getString("deleteUser")))
    {
      @Override
      public void onSubmit()
      { 
        try
        { 
          Node u = session.getJcrRootNode().getNode("users");
          u.getNode(theUserID).remove();
          u.save();
          
          theParent.setSelectedNode(null);
          theParent.updateDataAndView();
        }
        catch(RepositoryException ex)
        {
          Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
          error(ex.getMessage());
        }
      }
    };
    
    formDelete.add(btDelete);
    
    
    formPublish = new Form("formPublish");
    formEdit = new Form("formEdit");
    
    listOtherSectionsPublish = new ListMultipleChoice("listOtherSectionsPublish", 
      new Model(new LinkedList()),
      new LinkedList());
    listPublishAllowed = new ListMultipleChoice("listPublishAllowed",
      new Model(new LinkedList()),
      new LinkedList());
    listOtherSectionsEdit = new ListMultipleChoice("listOtherSectionsEdit",
      new Model(new LinkedList()),
      new LinkedList());
    listEditAllowed = new ListMultipleChoice("listEditAllowed",
      new Model(new LinkedList()),
      new LinkedList());
    
    listOtherSectionsPublish.setMaxRows(5);
    listOtherSectionsPublish.setRequired(false);
    listOtherSectionsPublish.setOutputMarkupId(true);
    
    listPublishAllowed.setMaxRows(5);
    listPublishAllowed.setRequired(false);
    listPublishAllowed.setOutputMarkupId(true);
    
    listOtherSectionsEdit.setMaxRows(5);
    listOtherSectionsEdit.setRequired(false);
    listOtherSectionsEdit.setOutputMarkupId(true);
    
    listEditAllowed.setMaxRows(5);
    listEditAllowed.setRequired(false);
    listEditAllowed.setOutputMarkupId(true);
    
    formPublish.add(listOtherSectionsPublish);
    formPublish.add(listPublishAllowed);
    formEdit.add(listEditAllowed);
    formEdit.add(listOtherSectionsEdit);
    
    btPublish = new AjaxButton("btPublish") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        addPublish();
        target.addComponent(feedback);
        target.addComponent(listPublishAllowed);
        target.addComponent(listOtherSectionsPublish);
      }
    };
    btPublish.setModel(new Model(getString("add")));
    
    btDePublish = new AjaxButton("btDePublish") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        deletePublish();
        target.addComponent(feedback);
        target.addComponent(listPublishAllowed);
        target.addComponent(listOtherSectionsPublish);
      }
    };
    btDePublish.setModel(new Model(getString("delete")));
    
    formPublish.add(btPublish);
    formPublish.add(btDePublish);
    
    btEdit = new AjaxButton("btEdit") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        addEdit();        
        target.addComponent(feedback);
        target.addComponent(listEditAllowed);
        target.addComponent(listOtherSectionsEdit);
      }
    };
    btEdit.setModel(new Model(getString("add")));
    
    btDeEdit = new AjaxButton("btDeEdit") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        deleteEdit();
        target.addComponent(feedback);
        target.addComponent(listEditAllowed);
        target.addComponent(listOtherSectionsEdit);
      }
    };
    btDeEdit.setModel(new Model(getString("delete")));
    
    formEdit.add(btEdit);
    formEdit.add(btDeEdit);
    
    formChange = new Form("formChange");
    
    txtRealName = new TextField("txtRealName", new Model(""));
    txtEMail = new TextField("txtEMail", new Model(""));
    txtPassword1 = new PasswordTextField("txtPassword1", new Model(""));
    txtPassword2 = new PasswordTextField("txtPassword2", new Model(""));
    txtPassword1.setRequired(false);
    txtPassword2.setRequired(false);
      
    cbIsAdmin = new CheckBox("cbIsAdmin", new Model(new Boolean(false)));
    
    btChange = new Button("btChange", new Model(getString("change")))
    {
      @Override
      public void onSubmit()
      {
        changeUserInfo();
      }
      
    };
    
    formChange.add(txtRealName);
    formChange.add(txtEMail);
    formChange.add(txtPassword1);
    formChange.add(txtPassword2);
    formChange.add(cbIsAdmin);
    formChange.add(btChange);
    
    add(formPublish);
    add(formEdit);
    add(formDelete);
    add(formChange);
    
    updateDataAndView();
    
  }
  
  private void changeUserInfo()
  {
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      Node userNode = rootNode.getNode("users").getNode(theUserID);
      
      userNode.setProperty("realname", txtRealName.getModelObjectAsString());
      userNode.setProperty("email", txtEMail.getModelObjectAsString());
      Boolean b = (Boolean) cbIsAdmin.getModelObject();
      userNode.setProperty("isadmin", b.booleanValue());

      boolean changedpwd = false;
      String pwd1 = txtPassword1.getModelObjectAsString();
      if(pwd1 != null && !"".equals(pwd1))
      {
        if(!pwd1.equals(txtPassword2.getModelObjectAsString()))
        {
          error(getString("passwordsnotequal"));
        }
        else
        {
          try
          {
            userNode.setProperty("passwordhash", Crypto.calculateSHAHash(pwd1));
            changedpwd = true;
          }
          catch(Exception ex)
          {
            Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
            error(getString("cryptoerror"));
          }          
        }
      }
      
      userNode.save();
      
      if(changedpwd)
      {
        info(getString("changeduserinfoandpwd"));
      }
      else
      {
        info(getString("changeduserinfo"));
      }
      
    }
    catch (RepositoryException ex)
    {
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
    
    updateDataAndView();
  }
  
  private void addPublish()
  {
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      
      List selection = (List) listOtherSectionsPublish.getModelObject();
      
      for(Object s : selection)
      {
        String sectionname = (String) s;

        if(!"".equals(sectionname))
        {

          if(rootNode.getNode("sections").hasNode(sectionname))
          {
            Node p = rootNode.getNode("users").getNode(theUserID).getNode("publish");

            if(!p.hasNode(sectionname))
            {
              p.addNode(sectionname);
              p.save();
            }
          }
          else
          {        
            error(getString("error"));        
          }
        }
      }
      
      updateLists();
       
      
    } 
    catch (RepositoryException ex)
    {
      error(getString("jcrerror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
  private void addEdit()
  {
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      
      List selection = (List) listOtherSectionsEdit.getModelObject();
      for(Object s : selection)
      {
        String sectionname = (String) s;
        if(!"".equals(sectionname))
        {

          if(rootNode.getNode("sections").hasNode(sectionname))
          {
            Node e = rootNode.getNode("users").getNode(theUserID).getNode("edit");

            if(!e.hasNode(sectionname))
            {
              e.addNode(sectionname);
              e.save();
            }
          }
          else
          {        
            error(getString("error"));        
          }
        }
      }
      updateLists();
    } 
    catch (RepositoryException ex)
    {
      error(getString("jcrerror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }    
  }
  
  private void deletePublish()
  {
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      
      List selection = (List) listPublishAllowed.getModelObject();
      for(Object s : selection)
      {
        String sectionname = (String) s;
        if(!"".equals(sectionname))
        {
          Node p = rootNode.getNode("users").getNode(theUserID).getNode("publish");
          if(p.hasNode(sectionname))
          {
            p.getNode(sectionname).remove();
            p.save();
          }
        }
      }
      
      updateLists();
      
    }
    catch (RepositoryException ex)
    {
      error(getString("jcrerror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
  private void deleteEdit()
  {
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      
      List selection = (List) listEditAllowed.getModelObject();
      for(Object s : selection)
      {
        String sectionname = (String) s;
        if(!"".equals(sectionname))
        {
          Node e = rootNode.getNode("users").getNode(theUserID).getNode("edit");
          if(e.hasNode(sectionname))
          {
            e.getNode(sectionname).remove();
            e.save();
          }
        }
      }
      updateLists();
      
    }
    catch (RepositoryException ex)
    {
      error(getString("jcrerror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
  private void updateLists()
  {
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      
      List<String> editAllowed = new LinkedList<String>();
      NodeIterator it = rootNode.getNode("users").getNode(theUserID).getNode("edit").getNodes();
      while(it.hasNext())
      {
        editAllowed.add(it.nextNode().getName());
      }
      Collections.sort(editAllowed);

      List<String> publishAllowed = new LinkedList<String>();
      it = rootNode.getNode("users").getNode(theUserID).getNode("publish").getNodes();
      while(it.hasNext())
      {
        publishAllowed.add(it.nextNode().getName());
      }
      Collections.sort(publishAllowed);
      
      List<String> allSections = new LinkedList<String>();
      it = rootNode.getNode("sections").getNodes();
      while(it.hasNext())
      {
        allSections.add(it.nextNode().getName());
      }
      
      List<String> editNotAllowed = new LinkedList<String>(allSections);
      editNotAllowed.removeAll(editAllowed);
      Collections.sort(editNotAllowed);
      
      List<String> publishNotAllowed = new LinkedList<String>(allSections);
      publishNotAllowed.removeAll(publishAllowed);
      Collections.sort(editNotAllowed);
      
      listOtherSectionsPublish.setChoices(publishNotAllowed);

      listPublishAllowed.setChoices(publishAllowed);

      listOtherSectionsEdit.setChoices(editNotAllowed);

      listEditAllowed.setChoices(editAllowed);

    }
    catch(RepositoryException ex)
    {
      Logger.getAnonymousLogger().log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
  }
  
  private void updateDataAndView()
  {
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      
      updateLists();

      Node userNode = rootNode.getNode("users").getNode(theUserID);

      txtRealName.setModelObject(userNode.getProperty("realname").getString());
      txtEMail.setModelObject(userNode.getProperty("email").getString());
      cbIsAdmin.setModelObject(userNode.getProperty("isadmin").getBoolean());
    }
    catch (RepositoryException ex)
    {
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }

  }
}